home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
101-125
/
scopedisk102
/
hamsharp
/
hamsharp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-19
|
22KB
|
835 lines
/* Copyright (C) 1989 by Ken C.M. Lau.
** Permission to use, copy, and distribute this software and its
** documentation for any purpose and without fee is hereby granted.
**
** Author : Ken Lau. June 89
** Purpose : Convert GIF file to IFF ham file
** Compiler : Aztec C 4.3a
** cc hamsharp.c
** cc hamsharp2.c
** cc hamsharp3.c
** cc hamsharp4.c
** ln hamsharp.o hamsharp2.o hamsharp3.o hamsharp4.o -lc -lm
*/
#include <stdio.h>
struct rgb {int r, g, b;};
struct remapelement {int pal, dist;};
long colorerr [256]; /* Histogram of errors */
long imageerr = 0L; /* Total error */
int colors; /* Colors in source */
int pals; /* Number of palette colors currently defined */
int planes; /* Planes in destination */
int hamflag; /* Set if picture requires HAM */
int picstep; /* Horizontal source pixels per dest pixel */
int picwidth; /* Destination pixels per line */
int scanstep = 2; /* Increase for faster processing */
int hamonly = 0; /* Set to process skip processing non-HAM */
int compression = -1; /* Set to 0 to switch off IFF compression */
int filenote = 0; /* Set to -1 to note error */
int edge = 1; /* Set to 0 for edge smoothing algorithm */
int update = 0; /* Set to 1 for skip existing files */
short iffbufsize = 16384; /* Default output file buffer size */
struct rgb palette [32]; /* Destination palette */
unsigned char **pic = NULL; /* Pointer to decompressed image in RAM */
struct remapelement remap [256]; /* Closest palette color to given color */
char gifname [80], iffname [80]; /* Source and destination files */
FILE *gif, *iff;
char *iffbuf = NULL; /* Pointer to output buffer */
/* GIF header info */
char signature [6];
struct {
unsigned width;
unsigned height;
unsigned char pixel;
unsigned char background;
unsigned char reserved;
} screen;
struct rgb cmap [256];
struct {
unsigned char seperator;
unsigned left;
unsigned top;
unsigned width;
unsigned height;
unsigned char pixel;
} image;
/* Main. Source and destination filenames may be specified in command line */
main(argc, argv)
char *argv[];
{
int bestcolor;
getargs(argc, argv); /* Set filenames */
initvars(); /* Allocate and initialize tables and variables */
while (getlist(gifname, iffname)) {
printf("Converting %s-->%s\n", gifname, iffname);
if (!readgif()) /* Decompress file into RAM pointed by pic */
goto nextfile;
palette [0] = cmap [0]; /* Background color is always assigned */
if (hamflag) {
if (edge) {
for (pals = 1; pals < 16; pals++) {
calcremap(); /* Calculate closest palette colors to remap to */
scanpic(); /* Scan pic and set colorerr [] */
bestcolor = findbest(); /* Pick a color to assign to palette */
palette [pals] = cmap [bestcolor];
printf("Palette %2d = colour %3d\x0D", pals, bestcolor);
printf("\x1B[40CImageErr = %7ld\n\x1BM", imageerr);
}
printf("\x1B[80K");
}
else
setpalette();
}
else {
for (pals = 1; pals < colors; pals++)
palette [pals] = cmap [pals];
}
calcremap();
if (!writeiff()) /* Use palette [] and remap [] */
goto nextfile;
printf("\x1B[1F\x1B[40K"); /* Erase image size stats */
printf("\x1BM\x1B[56C");
printf("ImageErr=%ld\n", imageerr);
nextfile:
freepic(); /* Free memory if required */
}
freevars();
}
/* Allocate and initialize tables and variables */
initvars()
{
char *calloc();
/* Allocate memory for file buffers */
iffbuf = calloc(iffbufsize, sizeof(char));
if (iffbuf == NULL)
fatalerr("Out of memory");
initrgberr();
}
/* Free memory for lookup tables */
freevars ()
{
if (iffbuf != NULL) {
free (iffbuf);
iffbuf = NULL;
}
freergberr ();
}
/* Print title page, get arguments from user if required */
getargs (argc, argv)
char *argv [];
{
int i;
printf ("\n");
printf (" HAMSHARP 1.5, GIF to IFF HAM converter, KL\n");
printf (" ------------------------------------------\n");
printf ("\n");
initlist ();
gifname[0] = iffname[0] = '\0';
for (i = 1; i < argc; i++)
if (argv[i][0] == '-') {
switch (tolower (argv[i][1])) {
case 's':
sscanf (argv[i], "%*c%*c%d", &scanstep);
break;
case 'h':
hamonly = -1;
break;
case 'c':
compression = 0;
break;
case 'b':
sscanf (argv [i], "%*c%*c%d", &iffbufsize);
break;
case 'f':
filenote = -1;
break;
case 'd':
edge = 0;
break;
case 'e':
edge = -1;
break;
case 'u':
update = -1;
break;
default:
fatalerr ("Illegal option");
break;
}
}
else {
if (gifname[0] == '\0') strcpy (gifname, argv[i]);
else if (iffname [0] == '\0') strcpy (iffname, argv[i]);
}
printf ("Source GIF filespec? ");
if (gifname [0] == '\0')
scanf ("%s", gifname);
else
printf ("%s\n", gifname);
printf ("Destn IFF filespec? ");
if (iffname [0] == '\0')
scanf ("%s", iffname);
else
printf ("%s\n", iffname);
if (scanstep <= 0)
fatalerr ("Scan step must be greater than 0");
getwild (); /* Read filenames matching wildcard from disk */
/* and add to list */
printf ("\n");
}
/* Decompress GIF file into RAM. Return error status */
readgif ()
{
if ((gif = fopen (gifname, "r")) == NULL) {
printf ("GIF file not found\n");
return (0);
}
if (!readheader ())
return (0);
if (hamonly && !hamflag) {
fclose (gif);
printf ("\x1BM\x1B[40K\x1BM\x1B[56C");
printf ("Not HAM\n");
return (0);
}
readpic ();
fclose (gif);
return (-1);
}
/* Print error message and halt */
fatalerr (s)
char *s;
{
printf (s);
printf ("\n");
freepic ();
freelist ();
freevars ();
exit (20);
}
/* Read header. Return error status */
readheader ()
{
int color;
fread (signature, 1, 6, gif);
if (strncmp (signature, "GIF87a", 6) != 0) {
printf ("Not GIF file\n");
return (0);
}
screen.width = readint ();
screen.height = readint ();
screen.pixel = getc (gif);
screen.background = getc (gif);
screen.reserved = getc (gif);
colors = 1 << ((screen.pixel & 0x07) + 1);
for (color = 0; color < colors; color++) {
cmap [color].r = getc (gif) >> 4;
cmap [color].g = getc (gif) >> 4;
cmap [color].b = getc (gif) >> 4;
}
image.seperator = getc (gif);
image.left = readint ();
image.top = readint ();
image.width = readint ();
image.height = readint ();
image.pixel = getc (gif);
if (image.seperator != ',') {
printf ("Missing seperator\n");
return (0);
}
if ((image.pixel & 0x80) != 0) {
printf ("Cannot handle local color map\n");
return (0);
}
printf ("%ux%ux%u\n", image.width, image.height, colors);
picstep = 1;
picwidth = image.width;
hamflag = (colors > 32) || ((colors > 16) && (image.width > 320));
if (hamflag && (image.width > 320)) {
picstep = 2;
picwidth = image.width / picstep;
}
planes = hamflag ? 6 : (screen.pixel & 7) + 1;
return (-1);
}
/* Read 16 bit quantity from GIF file, low byte first */
readint ()
{
int temp;
temp = getc (gif);
temp |= getc (gif) << 8;
return (temp);
}
unsigned char codesize; /* Used by readpic() and readcode() */
/* Read from gif file and write to iff file */
readpic()
{
int i;
int code, maxcode, clearcode, eofcode, curcode, oldcode, incode;
int freecode, firstfree;
unsigned char initcodesize, finchar, bitmask, *outptr;
static int prefix [4096];
static unsigned char suffix [4096], outcode [1025];
openadd ();
openreadcode ();
outptr = outcode;
bitmask = (1 << ((screen.pixel & 7) + 1)) - 1;
codesize = getc (gif);
clearcode = (1 << codesize);
eofcode = clearcode + 1;
freecode = firstfree = clearcode + 2;
codesize++;
initcodesize = codesize;
maxcode = (1 << codesize);
code = readcode ();
while (code != eofcode)
{
if (code == clearcode)
{
codesize = initcodesize;
maxcode = (1 << codesize);
freecode = firstfree;
curcode = oldcode = code = readcode ();
finchar = curcode;
addpixel (finchar);
}
else
{
curcode = incode = code;
if (curcode >= freecode)
{
curcode = oldcode;
*outptr++ = finchar;
}
while (curcode > bitmask)
{
#ifdef CHECK
if (outptr > outcode + 1024)
fatalerr ("Corrupt GIF file");
#endif
*outptr++ = suffix [curcode];
curcode = prefix [curcode];
}
finchar = curcode;
addpixel (finchar);
while (outptr != outcode)
addpixel (*--outptr);
prefix [freecode] = oldcode;
suffix [freecode] = finchar;
oldcode = incode;
if (++freecode >= maxcode)
{
#ifdef CHECK
if (codesize < 12)
{
#endif
codesize ++;
maxcode <<= 1;
#ifdef CHECK
}
#endif
}
}
code = readcode ();
}
if (getc (gif) != 0)
printf ("Warning: unaligned packet\n");
closereadcode ();
closeadd ();
}
static unsigned char bitmask = 0x00;
static int bytecount = 0;
/* Prepare to call readcode */
openreadcode ()
{
bytecount = bitmask = 0;
}
/* Fetch the next few bit from the source gif file */
readcode ()
{
static unsigned dsttbl [13] =
{1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80,
0x0100, 0x0200, 0x0400, 0x0800, 0x1000 };
static unsigned dstmasked = 0x0800;
static unsigned dstmask = 0x0001;
static int bytebuf = 0;
static unsigned temp;
temp = 0;
dstmasked = dsttbl [codesize];
for (dstmask = 0x0001; dstmask != dstmasked; dstmask <<= 1)
{
if (!bitmask)
{
bitmask = 0x01;
if (bytecount == 0)
bytecount = getc (gif);
bytebuf = getc (gif);
bytecount--;
}
if (bytebuf & bitmask)
temp |= dstmask;
bitmask <<= 1;
}
return (temp);
}
/* Finish reading code */
closereadcode ()
{
}
int xpic, ypic, xstate, leavepass;
unsigned char *linestart;
/* Prepare to add pixels to pic */
openadd ()
{
char *calloc ();
int y;
xpic = ypic = xstate = leavepass = 0;
if (image.pixel & 0x40)
leavepass = 2; /* GIF interleaved */
/* Allocate memory for the whole picture */
pic = (unsigned char **) calloc (image.height, sizeof (unsigned char *));
if (pic == NULL)
fatalerr ("Out of memory");
for (y = 0; y < image.height; y++) {
pic [y] = (unsigned char *) calloc (picwidth, sizeof (unsigned char));
if (pic [y] == NULL)
fatalerr ("Out of memory");
}
linestart = pic [0];
printf ("Decompressing line\n");
}
/* Add pixels to pic in RAM */
addpixel (pix)
{
static step [8] = {1, 0, 8, 8, 4, 2, 0}; /* GIF interleaved consts */
static first [8] = {0, 0, 0, 4, 2, 1, 0};
if (!xstate) {
xstate = picstep;
*linestart++ = pix;
}
xstate--;
xpic++;
if (xpic >= image.width) {
printf ("%3d\n\x1BM", ypic);
xpic = 0;
ypic += step [leavepass];
if (ypic >= image.height)
ypic = first [++leavepass];
linestart = pic [ypic];
}
}
/* Stop add pixels to RAM */
closeadd ()
{
printf (" \x1B[1F\x1B[40K\n\x1BM");
}
/* Free memory for picture */
freepic ()
{
int y;
if (pic == NULL)
return;
for (y = 0; y < image.height; y++)
free (pic [y]);
free (pic);
pic = NULL;
}
/* Calculate nearest palette color to given color */
calcremap ()
{
int color, pal, minpal, mindistance, distance, r, g, b;
int maxdistance = rgberr (0, 0, 0, 15, 15, 15);
struct rgb *c, *p;
for (color = 0; color < colors; color++) {
r = (c = & cmap [color]) -> r;
g = c->g;
b = c->b;
minpal = 0;
mindistance = maxdistance;
for (pal = 0; pal < pals; pal++) {
p = & palette [pal];
distance = rgberr (r, g, b, p->r, p->g, p->b);
if (distance < mindistance) {
mindistance = distance;
minpal = pal;
}
}
remap [color].pal = minpal;
remap [color].dist = mindistance;
}
}
/* Accumulate the error due to each color in the source image */
scanpic ()
{
unsigned char *linestart, *lineend;
int color, y, pix, select, gunerr, gunerr2, gunerr3;
struct rgb gun, want;
struct remapelement *remapp;
for (color = 0; color < colors; color++)
colorerr [color] = 0L;
for (y = 0; y < image.height; y += scanstep) {
gun = palette [0];
lineend = (linestart = pic [y]) + picwidth;
while (linestart != lineend) {
pix = *linestart++;
if (! (remapp = & remap [pix]) -> dist)
gun = palette [remapp->pal];
else {
want = cmap [pix];
gunerr = rgberr (want.r, gun.g, gun.b, want.r, want.g, want.b);
gunerr2 = rgberr (gun.r, want.g, gun.b, want.r, want.g, want.b);
gunerr3 = rgberr (gun.r, gun.g, want.b, want.r, want.g, want.b);
select = 0;
if (gunerr2 < gunerr) {
gunerr = gunerr2;
select = 1;
}
if (gunerr3 < gunerr) {
gunerr = gunerr3;
select = 2;
}
*(&gun.r + select) = *(&want.r + select);
if (remapp->dist < gunerr) {
gunerr = remapp->dist;
gun = palette [remapp->pal];
}
colorerr [pix] += gunerr;
}
}
}
}
/* Select colour to assign to palette given colorerr [] */
findbest ()
{
int bestcolor = 0;
long besterror = 0L;
int color;
imageerr = 0L; /* Estimated */
for (color = 0; color < colors; color++) {
if (colorerr [color] >= besterror) {
besterror = colorerr [color];
bestcolor = color;
}
imageerr += colorerr [color];
}
imageerr = (imageerr - besterror) * scanstep;
return (bestcolor);
}
/* Write IFF file from image in RAM given pic and remap [] */
/* Return error status */
writeiff ()
{
static char noteline [120];
if ((iff = fopen (iffname, "w")) == NULL) {
printf ("Cannot write to IFF file\n");
return (0);
}
/* Set up buffer for output */
if (iff->_buff)
fatalerr ("IFF buffer already allocated"); /* Should never occur */
iff->_buff = iffbuf;
iff->_buflen = iffbufsize;
writeheader ();
writepic (); /* with optional compression */
fixupheader (); /* body and form lengths fixups */
fclose (iff);
sprintf (noteline, "Err=%ld", imageerr);
if (filenote)
SetComment (iffname, noteline);
return (-1);
}
long formlenpsn, bodylenpsn;
/* Write header to IFF file */
writeheader ()
{
long ftell ();
int pal;
fputs ("FORM", iff); formlenpsn = ftell (iff); writelong (0L);
fputs ("ILBM", iff);
fputs ("BMHD", iff); writelong (20L);
writeint (picwidth); writeint (image.height); /* w, h */
writeint (image.left / picstep); /* x, y */
writeint (image.top);
putc (planes, iff); /* bitplanes */
putc (0, iff); /* masking */
putc (compression ? 1 : 0, iff); /* compression */
putc (0, iff); /* pad1 */
writeint (0); /* transparent color */
putc (10, iff); putc (11, iff); /* xAspect, yAspect */
writeint (screen.width / picstep); /* pagewidth, pageheight */
writeint (screen.height);
if (hamflag) {
fputs ("CAMG", iff); writelong (4L);
writelong (screen.height > 200 ? 0x4804L : 0x4800L);
}
fputs ("CMAP", iff); writelong ((long)(pals * 3));
for (pal = 0; pal < pals; pal++) {
putc (palette [pal].r << 4, iff);
putc (palette [pal].g << 4, iff);
putc (palette [pal].b << 4, iff);
}
fputs ("BODY", iff); bodylenpsn = ftell (iff); writelong (0L);
}
/* Write long integer to IFF file, high byte first */
writelong (a)
long a;
{
writeint ((unsigned) (a >> 16));
writeint ((unsigned) a);
}
/* Write unsigned integer to IFF file, high byte first */
writeint (a)
unsigned a;
{
putc (a >> 8, iff);
putc (a & 0xFF, iff);
}
/* Fixup IFF header */
fixupheader ()
{
long ftell ();
long bodylen = ftell (iff) - bodylenpsn - 4L;
long formlen = ftell (iff) - formlenpsn - 4L;
fseek (iff, bodylenpsn, 0); writelong (bodylen);
fseek (iff, formlenpsn, 0); writelong (formlen);
fseek (iff, 0L, 2);
}
/* Write out body of IFF file with optional compression */
writepic ()
{
long ftell ();
unsigned char *linestart, *lineend;
int y, pix, select, gunerr, gunerr2, gunerr3, colmask, planemask;
struct rgb gun, want;
struct remapelement *remapp;
int cols = (picwidth + 7) / 8;
static char pl[6][256];
static bitpsn, col, plane;
static compbuf [128];
static compbufi, compbufi1, compbufi2, state, disp, data;
static hambit [3] = {0x20, 0x30, 0x10};
imageerr = 0L;
printf ("Writing line\n");
for (y = 0; y < image.height; y++) {
printf ("%3d\n\x1BM", y);
col = 0;
colmask = 0x80;
gun = palette [0];
lineend = (linestart = pic [y]) + picwidth;
while (linestart != lineend) {
pix = *linestart++;
if (! (remapp = & remap [pix]) -> dist)
gun = palette [data = remapp->pal];
else {
want = cmap [pix];
gunerr = rgberr (want.r, gun.g, gun.b, want.r, want.g, want.b);
gunerr2 = rgberr (gun.r, want.g, gun.b, want.r, want.g, want.b);
gunerr3 = rgberr (gun.r, gun.g, want.b, want.r, want.g, want.b);
select = 0;
if (gunerr2 < gunerr) {
gunerr = gunerr2;
select = 1;
}
if (gunerr3 < gunerr) {
gunerr = gunerr3;
select = 2;
}
data = hambit [select]
| (*(&gun.r + select) = *(&want.r + select));
if (remapp->dist < gunerr) {
gunerr = remapp->dist;
gun = palette [data = remapp->pal];
}
imageerr += gunerr;
}
planemask = 0x01;
for (plane = 0; plane < planes; plane++) {
if (data & planemask)
pl [plane][col] |= colmask;
planemask <<= 1;
}
if (colmask == 0x01) {
colmask = 0x80;
col++;
}
else
colmask >>= 1;
}
if (!compression) {
for (plane = 0; plane < planes; plane++) {
for (col = 0; col < cols; col++) {
putc (pl [plane][col], iff);
pl [plane][col] = 0;
}
if (ftell (iff) & 1L)
putc (0, iff);
}
goto nextline;
}
for (plane = 0; plane < planes; plane ++) {
compbufi = 0;
state = 0;
data = pl[plane][0];
for (col = 1; col < cols; col ++)
switch (state) {
case 0:
if (data == pl[plane][col]) {
state = 1;
compbuf [compbufi] = col - 2 - compbufi;
compbufi = col - 1;
}
else
data = pl[plane][col];
break;
case 1:
if (data != pl[plane][col]) {
state = 0;
compbuf [compbufi] = compbufi - col + 1;
compbufi = col;
data = pl[plane][col];
}
break;
}
compbuf [compbufi] =
(state==0) ? cols-compbufi-1 : compbufi-cols+1;
state = 0;
compbufi = 0;
while (compbufi < cols) {
disp = compbuf [compbufi];
switch (state) {
case 0:
if (disp >= 0) {
state = 1;
compbufi1 = compbufi;
}
break;
case 1:
if (disp < 0) {
state = 2;
compbufi2 = compbufi;
}
else
compbufi1 = compbufi;
break;
case 2:
if (disp >= 0) {
state = 1;
if (compbuf [compbufi2] == -1) {
compbuf [compbufi1] += 3 + disp;
compbuf [compbufi2] = 0;
compbuf [compbufi] = 0;
}
else
compbufi1 = compbufi;
}
else
state = 0;
break;
}
compbufi += (disp >= 0) ? disp + 1 : -disp + 1;
}
compbufi = 0;
while (compbufi < cols) {
disp = compbuf [compbufi];
putc (disp, iff);
if (disp < 0) {
putc (pl [plane][compbufi], iff);
for (col = compbufi; col <= (compbufi - disp); col++)
pl [plane][col] = 0;
}
else
for (col = compbufi; col <= (compbufi + disp); col++) {
putc (pl [plane][col], iff);
pl [plane][col] = 0;
}
compbufi += (disp >= 0) ? disp + 1 : -disp + 1;
}
}
nextline:;
}
if (ftell (iff) & 1L)
putc (0, iff); /* Pad to word boundary */
printf (" \x1B[1F\x1B[40K\n\x1BM");
}